library("tidyverse")
library("data.table")
library("rtracklayer")
library("ggrastr")
library("DESeq2")
library("ggpubr")
library("wigglescout")
library("eulerr")
library("ggplot2")

# export 
result_folder = "../results/wigglescout/"

bws <- list.files("../data/CutNTag_ChIP-Seq/bw/",
                  full.names = TRUE)
# diff signal function
bw_granges_diff_analysis <- function(granges_c1,
                                     granges_c2,
                                     label_c1,
                                     label_c2,
                                     estimate_size_factors = FALSE,
                                     as_granges = FALSE) {
  # Bind first, get numbers after
  names_values <- NULL
  fields <- names(mcols(granges_c1))
  
  if ("name" %in% fields) {
    names_values <- mcols(granges_c1)[["name"]]
    granges_c1 <- granges_c1[, fields[fields != "name"]]
  }
  
  fields <- names(mcols(granges_c2))
  if ("name" %in% fields) {
    granges_c2 <- granges_c2[, fields[fields != "name"]]
  }
  
  cts_df <- cbind(data.frame(granges_c1), mcols(granges_c2))
  
  if (!is.null(names_values)) {
    rownames(cts_df) <- names_values
  }
  
  # Needs to drop non-complete cases and match rows
  complete <- complete.cases(cts_df)
  cts_df <- cts_df[complete, ]
  
  values_df <- cts_df[, 6:ncol(cts_df)] %>% dplyr::select(where(is.numeric))
  cts <- get_nreads_columns(values_df)
  
  condition_labels <- c(rep(label_c1, length(mcols(granges_c1))), rep(label_c2, length(mcols(granges_c2))))
  
  
  coldata <- data.frame(colnames(cts), condition = as.factor(condition_labels))
  print(coldata)
  
  dds <- DESeq2::DESeqDataSetFromMatrix(
    countData = cts,
    colData = coldata,
    design = ~ condition,
    rowRanges = granges_c1[complete, ]
  )
  
  
  if (estimate_size_factors == TRUE) {
    dds <- DESeq2::estimateSizeFactors(dds)
  }
  else {
    # Since files are scaled, we do not want to estimate size factors
    sizeFactors(dds) <- c(rep(1, ncol(cts)))
  }
  
  dds <- DESeq2::estimateDispersions(dds)
  dds <- DESeq2::nbinomWaldTest(dds)
  
  if (as_granges) {
    result <- DESeq2::results(dds, format = "GRanges", alpha = 0.01)
    if (!is.null(names_values)) {
      result$name <- names_values[complete]
    }
    
  }
  else {
    # result <- results(dds, format="DataFrame")
    result <- dds
  }
  
  result
}

get_nreads_columns <- function(df, length_factor = 100) {
  # Convert mean coverages to round integer read numbers
  cts <- as.matrix(df)
  cts <- as.matrix(cts[complete.cases(cts), ])
  cts <- round(cts * length_factor)
  cts
}
ctcf.and.G4.pro <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_with_promoters.sorted-CTCF_G4.bed")
ctcf.not.G4.pro <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_with_promoters.sorted-CTCFonly.bed")
ctcf.and.G4.npr <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_without_promoters.sorted-CTCF_G4.bed")
ctcf.not.G4.npr <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_without_promoters.sorted-CTCFonly.bed")

ctcf.and.G4.pro$class <- "CTCF_and_G4"
ctcf.not.G4.pro$class <- "CTCF_not_G4"
ctcf.and.G4.npr$class <- "CTCF_and_G4"
ctcf.not.G4.npr$class <- "CTCF_not_G4"
ctcf.and.G4.pro$pro <- "Pro"
ctcf.not.G4.pro$pro <- "Pro"
ctcf.and.G4.npr$pro <- "noPro"
ctcf.not.G4.npr$pro <- "noPro"

ctcf.and.G4 <- c(ctcf.and.G4.pro,ctcf.and.G4.npr)
ctcf.not.G4 <- c(ctcf.not.G4.pro,ctcf.not.G4.npr)
ctcf <- c(ctcf.and.G4,ctcf.not.G4)
ctcf <- sortSeqlevels(ctcf)
ctcf <- sort(ctcf)
names(ctcf) <- paste0(ctcf$class," ",ctcf$pro)
peaks_bed <- "../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories.bed"
export.bed(ctcf, "../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories.bed")
# Wulfridge CTCF ChIP-Seq mocks
mocks_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958387_GSM7116277_E14_Mock_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
          "../data/CutNTag_ChIP-Seq/bw/SRR23958386_GSM7116278_E14_Mock_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

# PDS
# Wulfridge CTCF ChIP-Seq
pds_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958385_GSM7116279_E14_PDS_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
                "../data/CutNTag_ChIP-Seq/bw/SRR23958384_GSM7116280_E14_PDS_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

pdc_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958383_GSM7116281_E14_PhenDC3_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
                "../data/CutNTag_ChIP-Seq/bw/SRR23958382_GSM7116282_E14_PhenDC3_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

G4_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/G4_CnT_NT_batch3_R1.unique.bw")

cov.mocks <- bw_loci(mocks_bigwigs,peaks_bed,labels=c("mock_1","mock_2"))
cov.pds <- bw_loci(pds_bigwigs,peaks_bed,labels=c("PDS_1","PDS_2"))
cov.pdc <- bw_loci(pdc_bigwigs,peaks_bed,labels=c("PhenDC3_1","PhenDC3_2"))
cov.G4 <- bw_loci(G4_bigwigs,peaks_bed,labels=c("G4_NT"))
results <- data.frame(
  as.data.frame(cov.mocks),
  as.data.frame(cov.pds)[6:7],
  as.data.frame(cov.pdc)[6:7],
  as.data.frame(cov.G4)[6],
  raw.lfc.pds_1 = log2(cov.pds$PDS_1/cov.mocks$mock_1),
  raw.lfc.pds_2 = log2(cov.pds$PDS_2/cov.mocks$mock_2),
  raw.lfc.pdc_1 = log2(cov.pds$PDS_1/cov.mocks$mock_1),
  raw.lfc.pdc_2 = log2(cov.pdc$PhenDC3_2/cov.mocks$mock_2),
  raw.lfc.pds = log2(rowMeans(as.data.frame(cov.pds)[6:7])/rowMeans(as.data.frame(cov.mocks)[6:7])),
  raw.lfc.pdc = log2(rowMeans(as.data.frame(cov.pdc)[6:7])/rowMeans(as.data.frame(cov.mocks)[6:7])),
  mean.mock = rowMeans(as.data.frame(cov.mocks)[6:7]),
  mean.pds = rowMeans(as.data.frame(cov.pds)[6:7]),
  mean.pdc = rowMeans(as.data.frame(cov.pdc)[6:7])
  )

cov.mocks$name <- NULL
cov.pds$name <- NULL
cov.pdc$name <- NULL

de_pds <- bw_granges_diff_analysis(cov.mocks,cov.pds,"Mock","PDS")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
lfc_pds = DESeq2::lfcShrink(de_pds, coef = "condition_PDS_vs_Mock", type = "apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
de_pdc <- bw_granges_diff_analysis(cov.mocks,cov.pdc,"Mock","PhenDC3")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
lfc_pdc = DESeq2::lfcShrink(de_pdc, coef = "condition_PhenDC3_vs_Mock", type = "apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
results$deseq.lfc.pds <- results(de_pds)$log2FoldChange
results$deseq.lfcs.pds <- lfc_pds$log2FoldChange
results$deseq.padj.pds <- lfc_pds$padj
results$deseq.mean.pds <- log2(lfc_pds$baseMean)
results$deseq.sig.pds <- lfc_pds$pvalue < 0.05

results$deseq.lfc.pdc <- results(de_pdc)$log2FoldChange
results$deseq.lfcs.pdc <- lfc_pdc$log2FoldChange
results$deseq.padj.pdc <- lfc_pdc$padj
results$deseq.mean.pdc <- log2(lfc_pdc$baseMean)
results$deseq.sig.pdc <- lfc_pdc$pvalue < 0.05

results$class <- gsub(" .+","",results$name)
results$pro <- gsub(".+ ","",results$name)
results$pro <- factor(results$pro, levels=c("Pro","noPro"))
results$class <- factor(results$class,levels=c("CTCF_and_G4","CTCF_not_G4"))

results$log2.mock <- log2(results$mean.mock)
results$log2.pds <- log2(results$mean.pds)
results$log2.pdc <- log2(results$mean.pdc)
results$log2.G4 <- log2(results$G4_NT)

results$deseq.sigup.pds <- results$deseq.sig.pds & results$deseq.lfc.pds > 0
results$deseq.sigup.pdc <- results$deseq.sig.pdc & results$deseq.lfc.pdc > 0
write.table(results,"foldchange_results.txt")
table(results$name)

CTCF_and_G4 noPro   CTCF_and_G4 Pro CTCF_not_G4 noPro   CTCF_not_G4 Pro 
              988              1300             43309              6016 
results <- read.table("foldchange_results.txt")
results$class <- factor(results$class, levels=c("CTCF_and_G4","CTCF_not_G4"))
mypal <-c("cornflowerblue","orange","red2","darkgreen","#505050")
mypal <-c("#00619D","#A82A34","orange","seagreen","#505050")
mypal2 <-c("#00619D","#7FB0CE","#A82A34","#D39499","orange","#FFD55A","seagreen","#7DBA9C","#505050")
p <- ggviolin(results,x ="class",y="mean.mock",fill="class",palette=mypal,add="median_iqr") + coord_cartesian(ylim=c(0,10))
annotate_figure(p,fig.lab = "CTCF signal by class in mock condition, mean of two reps, median+iqr",fig.lab.size = 6)

ggsave("Violin_CTCF_classes.pdf",last_plot())
Saving 3 x 3 in image
p <- ggviolin(results,x ="pro",y="mean.mock",fill="class",palette=mypal,add="median_iqr") + coord_cartesian(ylim=c(0,10))
annotate_figure(p,fig.lab = "CTCF signal by class in mock condition, mean of two reps, median+iqr",fig.lab.size = 6)

ggsave("Violin_CTCF_classes_pro.pdf",last_plot())
Saving 3 x 3 in image
mdf <- reshape2::melt(dplyr::select(results,c("class","mock_1","mock_2","PDS_1","PDS_2","PhenDC3_1","PhenDC3_2")))
Using class as id variables
ggboxplot(mdf,x ="variable",y="value",fill="class",palette=mypal ) + coord_cartesian(ylim=c(0,10))

ggsave("Boxplot_CTCF_reps.pdf",last_plot())
Saving 5 x 3 in image
mdf <- reshape2::melt(dplyr::select(results,c("class","mock_1","mock_2","PDS_1","PDS_2","PhenDC3_1","PhenDC3_2")))
Using class as id variables
ggviolin(mdf,x ="variable",y="value",fill="class",palette=mypal,add="median_iqr") + coord_cartesian(ylim=c(0,10))

ggsave("Violin_CTCF_reps.pdf",last_plot())
Saving 5 x 3 in image
mdf <- reshape2::melt(dplyr::select(results,c("class","deseq.lfc.pds","deseq.lfc.pdc")))
Using class as id variables
p <- ggviolin(mdf,x ="variable",y="value",fill="class",palette=mypal, add="median_iqr") + geom_hline(yintercept=0,linetype = "dotted") + coord_cartesian(ylim=c(-2,2))
annotate_figure(p,fig.lab = "DESEq foldchange mean treat vs mean mock, median+iqr",fig.lab.size = 6)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_CTCF_lfc.pdf",last_plot())
Saving 3 x 3 in image
p <- ggboxplot(mdf,x ="variable",y="value",fill="class",palette=mypal) + geom_hline(yintercept=0,linetype = "dotted") + coord_cartesian(ylim=c(-2,2))
annotate_figure(p,fig.lab = "DESEq foldchange mean treat vs mean mock, median+iqr",fig.lab.size = 6)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_boxplot()`).

ggsave("Boxplot_CTCF_lfc.pdf",last_plot())
Saving 3 x 3 in image
mdf <- reshape2::melt(dplyr::select(results,c("pro","class","deseq.lfc.pds","deseq.lfc.pdc")))
Using pro, class as id variables
p <- ggviolin(mdf,x ="pro",y="value",fill="class",palette=mypal, add="median_iqr", facet.by="variable") + geom_hline(yintercept=0,linetype = "dotted") + coord_cartesian(ylim=c(-2,2))
annotate_figure(p,fig.lab = "DESEq foldchange mean treat vs mean mock, median+iqr",fig.lab.size = 6)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_CTCF_lfc_pro.pdf",last_plot())
Saving 5 x 3 in image
compare_means(raw.lfc.pds ~ class,data = results)
compare_means(raw.lfc.pdc ~ class,data = results,)
mdf <- reshape2::melt(dplyr::select(results,c("class","raw.lfc.pds_1","raw.lfc.pds_2","raw.lfc.pdc_1","raw.lfc.pdc_2")))
Using class as id variables
ggviolin(mdf,x ="variable",y="value",fill="class",palette=mypal, add="median_iqr") + geom_hline(yintercept=0,linetype = "dotted") + coord_cartesian(ylim=c(-4,4))
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_CTCF_lfc_individual_reps.pdf",last_plot())
Saving 5 x 3 in image
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_summary()`).
ggdensity(results,x="raw.lfc.pds",color="class", fill="class",palette=mypal) + geom_vline(xintercept = 0, linetype ="dotted")
Warning: Removed 26 rows containing non-finite outside the scale range (`stat_density()`).

ggdensity(results,x="raw.lfc.pdc",color="class", fill="class",palette=mypal) + geom_vline(xintercept = 0, linetype ="dotted")
Warning: Removed 23 rows containing non-finite outside the scale range (`stat_density()`).

ggscatterhist(results,x ="log2.mock",y="log2.pds",size = 0.2, alpha=0.1,color="deseq.sig.pds",margin.params = list(fill="class",color="black",size=0.2),palette=mypal[c(5,2)])
Warning: Removed 15 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 12 rows containing non-finite outside the scale range (`stat_density()`).

ggsave("Scatter_CTCF_DESEq_PDSvsMock.pdf",last_plot())
Saving 4 x 4 in image
ggscatterhist(results,x ="log2.mock",y="log2.pdc",size = 0.2, alpha=0.1,color="deseq.sig.pds",margin.params = list(fill="class",color="black",size=0.2),palette=mypal[c(5,2)])
Warning: Removed 15 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 8 rows containing non-finite outside the scale range (`stat_density()`).

ggsave("Scatter_CTCF_DESEq_PhenDC3vsMock.pdf",last_plot())
Saving 4 x 4 in image
table(results$deseq.sig.pds & (results$deseq.lfc.pds > 0),results$pro)
       
        noPro   Pro
  FALSE 42094  6938
  TRUE   2200   378
table(results$deseq.sig.pds & (results$deseq.lfc.pds > 0),results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2220       46812
  TRUE           68        2510
mdf<-reshape2::melt(table(results$deseq.sig.pds & (results$deseq.lfc.pds > 0),results$class))
ggplot(mdf,aes(Var1, Var2, fill= value)) + 
  geom_tile(show.legend = F) + geom_text(aes(label=value)) +
  scale_fill_gradient(low="white", high="orange") + theme_minimal()

vl <- list(sig=grep("TRUE",results$deseq.sigup.pds),CTCF_G4=grep("and",results$class),CTCFonly=grep("not",results$class))
plot(euler(vl),quantities=T)

table(results$deseq.sig.pdc & (results$deseq.lfc.pdc > 0),results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2251       48545
  TRUE           37         780
mdf<-reshape2::melt(table(results$deseq.sig.pdc & (results$deseq.lfc.pdc > 0),results$class))
ggplot(mdf,aes(Var1, Var2, fill= value)) + 
  geom_tile(show.legend = F) + geom_text(aes(label=value)) +
  scale_fill_gradient(low="white", high="orange") + theme_minimal()

results$uid <- seq(1:nrow(results))
vl <- list(sig=grep("TRUE",results$deseq.sigup.pdc),CTCF_G4=grep("and",results$class),CTCFonly=grep("not",results$class))
plot(euler(vl),quantities=T)

table(results$deseq.sigup.pds,results$deseq.sigup.pdc)
       
        FALSE  TRUE
  FALSE 48576   456
  TRUE   2217   361
mdf<-reshape2::melt(table(results$deseq.sigup.pds,results$deseq.sigup.pdc))
ggplot(mdf,aes(Var1, Var2, fill= value)) + 
  geom_tile(show.legend = F) + geom_text(aes(label=value)) +
  scale_fill_gradient(low="white", high="orange") + theme_minimal()

vl <- list(sig_PDS=grep("TRUE",results$deseq.sigup.pds),sig_PDC=grep("TRUE",results$deseq.sigup.pdc),CTCF_G4=grep("and",results$class),CTCFonly=grep("not",results$class))
plot(euler(vl),quantities=T)

results$uid <- seq(1:nrow(results))
vl <- list(sig_PDS=grep("TRUE",results$deseq.sigup.pds),sig_PDC=grep("TRUE",results$deseq.sigup.pdc),CTCF_G4=grep("and",results$class))
plot(euler(vl),quantities=T)

results$sig.by.class.pds <- paste0(results$deseq.sigup.pds,"_",results$class)
results$psize <- 0.01
results$psize[results$deseq.sigup.pds & results$class=="CTCF_and_G4"] <- 1

ggscatter(results,x ="log2.mock",y="log2.pds",size = 0.5, alpha=results$psize,color = "sig.by.class.pds",palette=c(mypal[5],mypal[5],mypal[5],mypal[2],mypal[1]))

ggscatter(results[!grepl("NA",results$sig.by.class.pds),],x ="log2.mock",y="deseq.lfc.pds",size = 0.2, alpha="psize",color = "sig.by.class.pds",palette=c("#505050","#505050","red2","blue"))

ggscatterhist(results[!grepl("NA",results$sig.by.class.pds),],x ="log2.mock",y="log2.pds",size = 0.4, alpha="psize",color = "sig.by.class.pds",margin.params = list(fill="sig.by.class.pds",color="black",size=0.2),palette=c("#505050","#505050","red2","blue"))
Warning: Removed 13 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 10 rows containing non-finite outside the scale range (`stat_density()`).

ggscatter(results,x ="raw.lfc.pds",y="log2.G4",size = 0.2, alpha=0.1,color="deseq.sigup.pds")
Warning: Removed 1 row containing missing values or values outside the scale range (`geom_point()`).

results$G4.quantile <- cut_number(results$G4_NT, n = 5,labels=F)
ggstripchart(results,x="G4.quantile", y="deseq.lfc.pds",color=mypal[2],add=c("violin","median_iqr"),add.params=list(color="black",fill=mypal[1]),size=0.2, alpha=results$deseq.sig.pds/4, palette=mypal) + coord_cartesian(ylim=c(-3,3)) + geom_hline(yintercept = 0, linetype="dotted")
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
Warning: Removed 3 rows containing missing values or values outside the scale range (`geom_point()`).

ggsave("Violin_CTCF_lfc_by_G4quantile_sig_highlighted.pdf")
Saving 3 x 3 in image
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
Warning: Removed 3 rows containing missing values or values outside the scale range (`geom_point()`).
table(results$G4.quantile,results$deseq.sig.pds)
   
    FALSE TRUE
  1  9565  757
  2  9759  561
  3  9794  529
  4  9916  406
  5  9988  335
ggviolin(results,x="G4.quantile", y="deseq.lfc.pds",fill=mypal[1],add="median_iqr") + coord_cartesian(ylim=c(-2,2)) + geom_hline(yintercept = 0, linetype="dotted")
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_CTCF_lfc_by_G4quantile.pdf")
Saving 3 x 3 in image
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
ggviolin(results,x="G4.quantile", y="log2.G4",fill=mypal2[5],add="median_iqr") + geom_hline(yintercept = 0, linetype="dotted")
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_G4_by_G4quantile.pdf")
Saving 3 x 3 in image
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_summary()`).
peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile("../data/CutNTag_ChIP-Seq/bw/GSM6634325_E14_Mock_G4.bw",peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2284 generated ( 0.0527909395585346 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.053919121318023 per locus)

peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile(G4_bigwigs,peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal)

plot_bw_profile(mocks_bigwigs[1],peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2291 generated ( 0.0529527331561308 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 306 generated ( 0.0509236145781328 per locus)

p1 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[1]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
p2 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[2]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
p3 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[3]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
p4 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[4]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
ggarrange(p1,p2,p3,p4,ncol = 4,nrow = 1)

p1 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[1]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
p2 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[2]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
p3 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[3]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
p4 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[4]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
ggarrange(p1,p2,p3,p4,ncol = 4,nrow = 1)

cen we learn something from the genes with top-most increase in CTCF?

sigup.pds <- results[results$deseq.sigup.pds,]
sigup.pdc <- results[results$deseq.sigup.pdc,]

#export.bed(sigup.pds,"peaks_sigup_pds.bed")
#export.bed(sigup.pds,"peaks_sigup_pds.bed")
gghistogram(results,"width", add="median", fill="class")
Warning: Using `bins = 30` by default. Pick better value with the argument `bins`.

Overlap analysis

G4_bed <- import('../data/G4_CnT/G4_WT_peaks.narrowPeak')
ATAC_bed <- import('../data/ATAC-seq/ATAC_seq_mESC_Martire_peaks.narrowPeak')
pro_bed <- import('../data/regions/promoters_geneSymbol.mm10.bed')

G4_bed <- bedscout::annotate_overlapping_features(G4_bed,pro_bed,name_field = "name")

G4_bed$name <- "G4"
G4_bed$name[!is.na(G4_bed$nearby_features)] <- "G4pro"
G4_bed$name[grepl("pro",G4_bed$name)] <- "G4pro"
nearest_G4_1kb <- bedscout::annotate_nearby_features(ctcf,G4_bed,distance_cutoff = 1000,ignore.strand = T,name_field = "name")
nearest_G4_2.5kb <- bedscout::annotate_nearby_features(ctcf,G4_bed,distance_cutoff = 2500,ignore.strand = T,name_field = "name")
nearest_G4_5kb <- bedscout::annotate_nearby_features(ctcf,G4_bed,distance_cutoff = 5000,ignore.strand = T,name_field = "name")
nearest_G4_10kb <- bedscout::annotate_nearby_features(ctcf,G4_bed,distance_cutoff = 10000,ignore.strand = T,name_field = "name")
nearest_G4_50kb <- bedscout::annotate_nearby_features(ctcf,G4_bed,distance_cutoff = 50000,ignore.strand = T,name_field = "name")

ctcf$nearest_G4 <- factor(">50kb", levels=c("<1kb","<2.5kb","<5kb","<10kb","<50kb",">50kb"))
ctcf$nearest_G4[!is.na(nearest_G4_50kb$nearby_features)] <- "<50kb"
ctcf$nearest_G4[!is.na(nearest_G4_10kb$nearby_features)] <- "<10kb"
ctcf$nearest_G4[!is.na(nearest_G4_5kb$nearby_features)] <- "<5kb"
ctcf$nearest_G4[!is.na(nearest_G4_2.5kb$nearby_features)] <- "<2.5kb"
ctcf$nearest_G4[!is.na(nearest_G4_1kb$nearby_features)] <- "<1kb"

ctcf$nearest_G4_type <- "none"
ctcf$nearest_G4_type[!is.na(nearest_G4_50kb$nearby_features)] <- nearest_G4_50kb$nearby_features[!is.na(nearest_G4_50kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_10kb$nearby_features)] <- nearest_G4_10kb$nearby_features[!is.na(nearest_G4_10kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_5kb$nearby_features)] <- nearest_G4_5kb$nearby_features[!is.na(nearest_G4_5kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_2.5kb$nearby_features)] <- nearest_G4_2.5kb$nearby_features[!is.na(nearest_G4_2.5kb$nearby_features)]
ctcf$nearest_G4_type[!is.na(nearest_G4_1kb$nearby_features)] <- nearest_G4_1kb$nearby_features[!is.na(nearest_G4_1kb$nearby_features)]

ctcf$nearest_G4_type[grep("pro",ctcf$nearest_G4_type)] <- "G4pro"

results$nearest_G4 <- ctcf$nearest_G4
results$nearest_G4_type <- ctcf$nearest_G4_type
table(results$nearest_G4)

  <1kb <2.5kb   <5kb  <10kb  <50kb  >50kb 
  3540   1558   2350   4285  20140  19740 
table(results$nearest_G4_type)

   G4 G4pro  none 
11457 20416 19740 
table(results$nearest_G4, results$nearest_G4_type)
        
            G4 G4pro  none
  <1kb    1426  2114     0
  <2.5kb   581   977     0
  <5kb     948  1402     0
  <10kb   1675  2610     0
  <50kb   6827 13313     0
  >50kb      0     0 19740
ggviolin(results,x="nearest_G4", y="mean.mock",fill=mypal[1],add="median_iqr") + coord_cartesian(ylim=c(0,10)) + geom_hline(yintercept = 0, linetype="dotted")

ggsave("Violin_CTCF_signal_by_G4distance.pdf")
Saving 3 x 3 in image
ggviolin(results,x="nearest_G4", y="deseq.lfc.pds",fill=mypal[1],add="median_iqr") + coord_cartesian(ylim=c(-2,2)) + geom_hline(yintercept = 0,linewidth = 0.2 ) + geom_hline(yintercept = median(results$deseq.lfc.pds[results$nearest_G4=="<1kb"]), linetype="dotted",linewidth = 0.2)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_CTCF_PDS_lfc_by_G4distance.pdf")
Saving 3 x 3 in image
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
compare_means(deseq.lfc.pds ~ nearest_G4, results)
ggviolin(results,x="nearest_G4", y="deseq.lfc.pdc",fill=mypal[1],add="median_iqr") + coord_cartesian(ylim=c(-2,2)) + geom_hline(yintercept = 0,linewidth = 0.2 ) + geom_hline(yintercept = mean(results$deseq.lfc.pdc[results$nearest_G4=="<1kb"]), linetype="dotted",linewidth = 0.2)

ggsave("Violin_CTCF_PhenDC3_lfc_by_G4distance.pdf")
Saving 3 x 3 in image
compare_means(deseq.lfc.pdc ~ nearest_G4, results)
ggviolin(results,x="nearest_G4", y="deseq.lfc.pds",fill="nearest_G4_type",palette=mypal[c(1,3,5)],add="median_iqr") + coord_cartesian(ylim=c(-2,2)) + geom_hline(yintercept = 0,linewidth = 0.2 ) + geom_hline(yintercept = mean(results$deseq.lfc.pds[results$nearest_G4=="<1kb"]), linetype="dotted",linewidth = 0.2)
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggsave("Violin_CTCF_PDS_lfc_by_G4distance_pro.pdf")
Saving 5 x 3 in image
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$nearest_G4_type=="G4",])
compare_means(deseq.lfc.pds ~ nearest_G4, results[results$nearest_G4_type=="G4pro",])
ggviolin(results,x="nearest_G4", y="deseq.lfc.pdc",fill="nearest_G4_type",palette=mypal[c(1,3,5)],add="median_iqr") + coord_cartesian(ylim=c(-2,2)) + geom_hline(yintercept = 0,linewidth = 0.2) + geom_hline(yintercept = mean(results$deseq.lfc.pdc[results$nearest_G4=="<1kb"]), linetype="dotted",linewidth = 0.2)

ggsave("Violin_CTCF_PhenDC3_lfc_by_G4distance_pro.pdf")
Saving 5 x 3 in image
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$nearest_G4_type=="G4",])
compare_means(deseq.lfc.pdc ~ nearest_G4, results[results$nearest_G4_type=="G4pro",])
peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile("../data/regions/G4.mm10.plus.bw",peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, colors=mypal)

peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile("../data/regions/G4.mm10.minus.bw",peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, colors=mypal)

peak_cats_mm9 <- bedscout::import_named_bed_into_list('../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories.mm9lift.bed')
plot_bw_profile("~/Google Drive/Simon/Manuscripts/Puck/github/genome/mm9/predG4.mm9.bw",peak_cats_mm9,labels=c(peak_cats_mm9[[1]][1,]$name,peak_cats_mm9[[2]][1,]$name,peak_cats_mm9[[3]][1,]$name,peak_cats_mm9[[4]][1,]$name),mode="center",show_error = T,verbose=F, colors=mypal)

ggsave("Profile_predicted_G4_motif.pdf")
Saving 7 x 7 in image
ggprofile("Profile_predicted_G4_motif.pdf")
Error in ggprofile("Profile_predicted_G4_motif.pdf") : 
  could not find function "ggprofile"
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJkYXRhLnRhYmxlIikKbGlicmFyeSgicnRyYWNrbGF5ZXIiKQpsaWJyYXJ5KCJnZ3Jhc3RyIikKbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZ2dwdWJyIikKbGlicmFyeSgid2lnZ2xlc2NvdXQiKQpsaWJyYXJ5KCJldWxlcnIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKCiMgZXhwb3J0IApyZXN1bHRfZm9sZGVyID0gIi4uL3Jlc3VsdHMvd2lnZ2xlc2NvdXQvIgoKYndzIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy8iLAogICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkKCmBgYAoKYGBge3J9CiMgZGlmZiBzaWduYWwgZnVuY3Rpb24KYndfZ3Jhbmdlc19kaWZmX2FuYWx5c2lzIDwtIGZ1bmN0aW9uKGdyYW5nZXNfYzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFuZ2VzX2MyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfYzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlX3NpemVfZmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfZ3JhbmdlcyA9IEZBTFNFKSB7CiAgIyBCaW5kIGZpcnN0LCBnZXQgbnVtYmVycyBhZnRlcgogIG5hbWVzX3ZhbHVlcyA8LSBOVUxMCiAgZmllbGRzIDwtIG5hbWVzKG1jb2xzKGdyYW5nZXNfYzEpKQogIAogIGlmICgibmFtZSIgJWluJSBmaWVsZHMpIHsKICAgIG5hbWVzX3ZhbHVlcyA8LSBtY29scyhncmFuZ2VzX2MxKVtbIm5hbWUiXV0KICAgIGdyYW5nZXNfYzEgPC0gZ3Jhbmdlc19jMVssIGZpZWxkc1tmaWVsZHMgIT0gIm5hbWUiXV0KICB9CiAgCiAgZmllbGRzIDwtIG5hbWVzKG1jb2xzKGdyYW5nZXNfYzIpKQogIGlmICgibmFtZSIgJWluJSBmaWVsZHMpIHsKICAgIGdyYW5nZXNfYzIgPC0gZ3Jhbmdlc19jMlssIGZpZWxkc1tmaWVsZHMgIT0gIm5hbWUiXV0KICB9CiAgCiAgY3RzX2RmIDwtIGNiaW5kKGRhdGEuZnJhbWUoZ3Jhbmdlc19jMSksIG1jb2xzKGdyYW5nZXNfYzIpKQogIAogIGlmICghaXMubnVsbChuYW1lc192YWx1ZXMpKSB7CiAgICByb3duYW1lcyhjdHNfZGYpIDwtIG5hbWVzX3ZhbHVlcwogIH0KICAKICAjIE5lZWRzIHRvIGRyb3Agbm9uLWNvbXBsZXRlIGNhc2VzIGFuZCBtYXRjaCByb3dzCiAgY29tcGxldGUgPC0gY29tcGxldGUuY2FzZXMoY3RzX2RmKQogIGN0c19kZiA8LSBjdHNfZGZbY29tcGxldGUsIF0KICAKICB2YWx1ZXNfZGYgPC0gY3RzX2RmWywgNjpuY29sKGN0c19kZildICU+JSBkcGx5cjo6c2VsZWN0KHdoZXJlKGlzLm51bWVyaWMpKQogIGN0cyA8LSBnZXRfbnJlYWRzX2NvbHVtbnModmFsdWVzX2RmKQogIAogIGNvbmRpdGlvbl9sYWJlbHMgPC0gYyhyZXAobGFiZWxfYzEsIGxlbmd0aChtY29scyhncmFuZ2VzX2MxKSkpLCByZXAobGFiZWxfYzIsIGxlbmd0aChtY29scyhncmFuZ2VzX2MyKSkpKQogIAogIAogIGNvbGRhdGEgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyhjdHMpLCBjb25kaXRpb24gPSBhcy5mYWN0b3IoY29uZGl0aW9uX2xhYmVscykpCiAgcHJpbnQoY29sZGF0YSkKICAKICBkZHMgPC0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KAogICAgY291bnREYXRhID0gY3RzLAogICAgY29sRGF0YSA9IGNvbGRhdGEsCiAgICBkZXNpZ24gPSB+IGNvbmRpdGlvbiwKICAgIHJvd1JhbmdlcyA9IGdyYW5nZXNfYzFbY29tcGxldGUsIF0KICApCiAgCiAgCiAgaWYgKGVzdGltYXRlX3NpemVfZmFjdG9ycyA9PSBUUlVFKSB7CiAgICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKICB9CiAgZWxzZSB7CiAgICAjIFNpbmNlIGZpbGVzIGFyZSBzY2FsZWQsIHdlIGRvIG5vdCB3YW50IHRvIGVzdGltYXRlIHNpemUgZmFjdG9ycwogICAgc2l6ZUZhY3RvcnMoZGRzKSA8LSBjKHJlcCgxLCBuY29sKGN0cykpKQogIH0KICAKICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZURpc3BlcnNpb25zKGRkcykKICBkZHMgPC0gREVTZXEyOjpuYmlub21XYWxkVGVzdChkZHMpCiAgCiAgaWYgKGFzX2dyYW5nZXMpIHsKICAgIHJlc3VsdCA8LSBERVNlcTI6OnJlc3VsdHMoZGRzLCBmb3JtYXQgPSAiR1JhbmdlcyIsIGFscGhhID0gMC4wMSkKICAgIGlmICghaXMubnVsbChuYW1lc192YWx1ZXMpKSB7CiAgICAgIHJlc3VsdCRuYW1lIDwtIG5hbWVzX3ZhbHVlc1tjb21wbGV0ZV0KICAgIH0KICAgIAogIH0KICBlbHNlIHsKICAgICMgcmVzdWx0IDwtIHJlc3VsdHMoZGRzLCBmb3JtYXQ9IkRhdGFGcmFtZSIpCiAgICByZXN1bHQgPC0gZGRzCiAgfQogIAogIHJlc3VsdAp9CgpnZXRfbnJlYWRzX2NvbHVtbnMgPC0gZnVuY3Rpb24oZGYsIGxlbmd0aF9mYWN0b3IgPSAxMDApIHsKICAjIENvbnZlcnQgbWVhbiBjb3ZlcmFnZXMgdG8gcm91bmQgaW50ZWdlciByZWFkIG51bWJlcnMKICBjdHMgPC0gYXMubWF0cml4KGRmKQogIGN0cyA8LSBhcy5tYXRyaXgoY3RzW2NvbXBsZXRlLmNhc2VzKGN0cyksIF0pCiAgY3RzIDwtIHJvdW5kKGN0cyAqIGxlbmd0aF9mYWN0b3IpCiAgY3RzCn0KYGBgCgpgYGB7cn0KY3RjZi5hbmQuRzQucHJvIDwtIGltcG9ydCgiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXNfd2l0aF9wcm9tb3RlcnMuc29ydGVkLUNUQ0ZfRzQuYmVkIikKY3RjZi5ub3QuRzQucHJvIDwtIGltcG9ydCgiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXNfd2l0aF9wcm9tb3RlcnMuc29ydGVkLUNUQ0Zvbmx5LmJlZCIpCmN0Y2YuYW5kLkc0Lm5wciA8LSBpbXBvcnQoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9iZWQvV3VsZnJpZGdlX0NUQ0ZfaW5fNl9jYXRlZ29yaWVzX3dpdGhvdXRfcHJvbW90ZXJzLnNvcnRlZC1DVENGX0c0LmJlZCIpCmN0Y2Yubm90Lkc0Lm5wciA8LSBpbXBvcnQoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9iZWQvV3VsZnJpZGdlX0NUQ0ZfaW5fNl9jYXRlZ29yaWVzX3dpdGhvdXRfcHJvbW90ZXJzLnNvcnRlZC1DVENGb25seS5iZWQiKQoKY3RjZi5hbmQuRzQucHJvJGNsYXNzIDwtICJDVENGX2FuZF9HNCIKY3RjZi5ub3QuRzQucHJvJGNsYXNzIDwtICJDVENGX25vdF9HNCIKY3RjZi5hbmQuRzQubnByJGNsYXNzIDwtICJDVENGX2FuZF9HNCIKY3RjZi5ub3QuRzQubnByJGNsYXNzIDwtICJDVENGX25vdF9HNCIKY3RjZi5hbmQuRzQucHJvJHBybyA8LSAiUHJvIgpjdGNmLm5vdC5HNC5wcm8kcHJvIDwtICJQcm8iCmN0Y2YuYW5kLkc0Lm5wciRwcm8gPC0gIm5vUHJvIgpjdGNmLm5vdC5HNC5ucHIkcHJvIDwtICJub1BybyIKCmN0Y2YuYW5kLkc0IDwtIGMoY3RjZi5hbmQuRzQucHJvLGN0Y2YuYW5kLkc0Lm5wcikKY3RjZi5ub3QuRzQgPC0gYyhjdGNmLm5vdC5HNC5wcm8sY3RjZi5ub3QuRzQubnByKQpjdGNmIDwtIGMoY3RjZi5hbmQuRzQsY3RjZi5ub3QuRzQpCmN0Y2YgPC0gc29ydFNlcWxldmVscyhjdGNmKQpjdGNmIDwtIHNvcnQoY3RjZikKbmFtZXMoY3RjZikgPC0gcGFzdGUwKGN0Y2YkY2xhc3MsIiAiLGN0Y2YkcHJvKQpwZWFrc19iZWQgPC0gIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9iZWQvV3VsZnJpZGdlX0NUQ0ZfaW5fNl9jYXRlZ29yaWVzLmJlZCIKZXhwb3J0LmJlZChjdGNmLCAiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXMuYmVkIikKYGBgCgpgYGB7cn0KIyBXdWxmcmlkZ2UgQ1RDRiBDaElQLVNlcSBtb2Nrcwptb2Nrc19iaWd3aWdzID0gYygiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L1NSUjIzOTU4Mzg3X0dTTTcxMTYyNzdfRTE0X01vY2tfQ1RDRl9SZXAxX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IiwKICAgICAgICAgICIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvU1JSMjM5NTgzODZfR1NNNzExNjI3OF9FMTRfTW9ja19DVENGX1JlcDJfTXVzX211c2N1bHVzX0NoSVAtU2VxLkNQTW5vcm0uYnciKQoKIyBQRFMKIyBXdWxmcmlkZ2UgQ1RDRiBDaElQLVNlcQpwZHNfYmlnd2lncyA9IGMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy9TUlIyMzk1ODM4NV9HU003MTE2Mjc5X0UxNF9QRFNfQ1RDRl9SZXAxX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IiwKICAgICAgICAgICAgICAgICIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvU1JSMjM5NTgzODRfR1NNNzExNjI4MF9FMTRfUERTX0NUQ0ZfUmVwMl9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIpCgpwZGNfYmlnd2lncyA9IGMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy9TUlIyMzk1ODM4M19HU003MTE2MjgxX0UxNF9QaGVuREMzX0NUQ0ZfUmVwMV9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIsCiAgICAgICAgICAgICAgICAiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L1NSUjIzOTU4MzgyX0dTTTcxMTYyODJfRTE0X1BoZW5EQzNfQ1RDRl9SZXAyX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IikKCkc0X2JpZ3dpZ3MgPSBjKCIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvRzRfQ25UX05UX2JhdGNoM19SMS51bmlxdWUuYnciKQoKY292Lm1vY2tzIDwtIGJ3X2xvY2kobW9ja3NfYmlnd2lncyxwZWFrc19iZWQsbGFiZWxzPWMoIm1vY2tfMSIsIm1vY2tfMiIpKQpjb3YucGRzIDwtIGJ3X2xvY2kocGRzX2JpZ3dpZ3MscGVha3NfYmVkLGxhYmVscz1jKCJQRFNfMSIsIlBEU18yIikpCmNvdi5wZGMgPC0gYndfbG9jaShwZGNfYmlnd2lncyxwZWFrc19iZWQsbGFiZWxzPWMoIlBoZW5EQzNfMSIsIlBoZW5EQzNfMiIpKQpjb3YuRzQgPC0gYndfbG9jaShHNF9iaWd3aWdzLHBlYWtzX2JlZCxsYWJlbHM9YygiRzRfTlQiKSkKYGBgCgoKYGBge3J9CnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBhcy5kYXRhLmZyYW1lKGNvdi5tb2NrcyksCiAgYXMuZGF0YS5mcmFtZShjb3YucGRzKVs2OjddLAogIGFzLmRhdGEuZnJhbWUoY292LnBkYylbNjo3XSwKICBhcy5kYXRhLmZyYW1lKGNvdi5HNClbNl0sCiAgcmF3LmxmYy5wZHNfMSA9IGxvZzIoY292LnBkcyRQRFNfMS9jb3YubW9ja3MkbW9ja18xKSwKICByYXcubGZjLnBkc18yID0gbG9nMihjb3YucGRzJFBEU18yL2Nvdi5tb2NrcyRtb2NrXzIpLAogIHJhdy5sZmMucGRjXzEgPSBsb2cyKGNvdi5wZHMkUERTXzEvY292Lm1vY2tzJG1vY2tfMSksCiAgcmF3LmxmYy5wZGNfMiA9IGxvZzIoY292LnBkYyRQaGVuREMzXzIvY292Lm1vY2tzJG1vY2tfMiksCiAgcmF3LmxmYy5wZHMgPSBsb2cyKHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LnBkcylbNjo3XSkvcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YubW9ja3MpWzY6N10pKSwKICByYXcubGZjLnBkYyA9IGxvZzIocm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YucGRjKVs2OjddKS9yb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5tb2NrcylbNjo3XSkpLAogIG1lYW4ubW9jayA9IHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292Lm1vY2tzKVs2OjddKSwKICBtZWFuLnBkcyA9IHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LnBkcylbNjo3XSksCiAgbWVhbi5wZGMgPSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5wZGMpWzY6N10pCiAgKQoKY292Lm1vY2tzJG5hbWUgPC0gTlVMTApjb3YucGRzJG5hbWUgPC0gTlVMTApjb3YucGRjJG5hbWUgPC0gTlVMTAoKZGVfcGRzIDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YubW9ja3MsY292LnBkcywiTW9jayIsIlBEUyIpCmxmY19wZHMgPSBERVNlcTI6OmxmY1NocmluayhkZV9wZHMsIGNvZWYgPSAiY29uZGl0aW9uX1BEU192c19Nb2NrIiwgdHlwZSA9ICJhcGVnbG0iKQoKZGVfcGRjIDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YubW9ja3MsY292LnBkYywiTW9jayIsIlBoZW5EQzMiKQpsZmNfcGRjID0gREVTZXEyOjpsZmNTaHJpbmsoZGVfcGRjLCBjb2VmID0gImNvbmRpdGlvbl9QaGVuREMzX3ZzX01vY2siLCB0eXBlID0gImFwZWdsbSIpCgpyZXN1bHRzJGRlc2VxLmxmYy5wZHMgPC0gcmVzdWx0cyhkZV9wZHMpJGxvZzJGb2xkQ2hhbmdlCnJlc3VsdHMkZGVzZXEubGZjcy5wZHMgPC0gbGZjX3BkcyRsb2cyRm9sZENoYW5nZQpyZXN1bHRzJGRlc2VxLnBhZGoucGRzIDwtIGxmY19wZHMkcGFkagpyZXN1bHRzJGRlc2VxLm1lYW4ucGRzIDwtIGxvZzIobGZjX3BkcyRiYXNlTWVhbikKcmVzdWx0cyRkZXNlcS5zaWcucGRzIDwtIGxmY19wZHMkcHZhbHVlIDwgMC4wNQoKcmVzdWx0cyRkZXNlcS5sZmMucGRjIDwtIHJlc3VsdHMoZGVfcGRjKSRsb2cyRm9sZENoYW5nZQpyZXN1bHRzJGRlc2VxLmxmY3MucGRjIDwtIGxmY19wZGMkbG9nMkZvbGRDaGFuZ2UKcmVzdWx0cyRkZXNlcS5wYWRqLnBkYyA8LSBsZmNfcGRjJHBhZGoKcmVzdWx0cyRkZXNlcS5tZWFuLnBkYyA8LSBsb2cyKGxmY19wZGMkYmFzZU1lYW4pCnJlc3VsdHMkZGVzZXEuc2lnLnBkYyA8LSBsZmNfcGRjJHB2YWx1ZSA8IDAuMDUKCnJlc3VsdHMkY2xhc3MgPC0gZ3N1YigiIC4rIiwiIixyZXN1bHRzJG5hbWUpCnJlc3VsdHMkcHJvIDwtIGdzdWIoIi4rICIsIiIscmVzdWx0cyRuYW1lKQpyZXN1bHRzJHBybyA8LSBmYWN0b3IocmVzdWx0cyRwcm8sIGxldmVscz1jKCJQcm8iLCJub1BybyIpKQpyZXN1bHRzJGNsYXNzIDwtIGZhY3RvcihyZXN1bHRzJGNsYXNzLGxldmVscz1jKCJDVENGX2FuZF9HNCIsIkNUQ0Zfbm90X0c0IikpCgpyZXN1bHRzJGxvZzIubW9jayA8LSBsb2cyKHJlc3VsdHMkbWVhbi5tb2NrKQpyZXN1bHRzJGxvZzIucGRzIDwtIGxvZzIocmVzdWx0cyRtZWFuLnBkcykKcmVzdWx0cyRsb2cyLnBkYyA8LSBsb2cyKHJlc3VsdHMkbWVhbi5wZGMpCnJlc3VsdHMkbG9nMi5HNCA8LSBsb2cyKHJlc3VsdHMkRzRfTlQpCgpyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyA8LSByZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiByZXN1bHRzJGRlc2VxLmxmYy5wZHMgPiAwCnJlc3VsdHMkZGVzZXEuc2lndXAucGRjIDwtIHJlc3VsdHMkZGVzZXEuc2lnLnBkYyAmIHJlc3VsdHMkZGVzZXEubGZjLnBkYyA+IDAKYGBgCgpgYGB7cn0Kd3JpdGUudGFibGUocmVzdWx0cywiZm9sZGNoYW5nZV9yZXN1bHRzLnR4dCIpCnRhYmxlKHJlc3VsdHMkbmFtZSkKYGBgCgpgYGB7cn0KcmVzdWx0cyA8LSByZWFkLnRhYmxlKCJmb2xkY2hhbmdlX3Jlc3VsdHMudHh0IikKcmVzdWx0cyRjbGFzcyA8LSBmYWN0b3IocmVzdWx0cyRjbGFzcywgbGV2ZWxzPWMoIkNUQ0ZfYW5kX0c0IiwiQ1RDRl9ub3RfRzQiKSkKYGBgCgpgYGB7cn0KbXlwYWwgPC1jKCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiLCJkYXJrZ3JlZW4iLCIjNTA1MDUwIikKbXlwYWwgPC1jKCIjMDA2MTlEIiwiI0E4MkEzNCIsIm9yYW5nZSIsInNlYWdyZWVuIiwiIzUwNTA1MCIpCm15cGFsMiA8LWMoIiMwMDYxOUQiLCIjN0ZCMENFIiwiI0E4MkEzNCIsIiNEMzk0OTkiLCJvcmFuZ2UiLCIjRkZENTVBIiwic2VhZ3JlZW4iLCIjN0RCQTlDIiwiIzUwNTA1MCIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcCA8LSBnZ3Zpb2xpbihyZXN1bHRzLHggPSJjbGFzcyIseT0ibWVhbi5tb2NrIixmaWxsPSJjbGFzcyIscGFsZXR0ZT1teXBhbCxhZGQ9Im1lZGlhbl9pcXIiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmFubm90YXRlX2ZpZ3VyZShwLGZpZy5sYWIgPSAiQ1RDRiBzaWduYWwgYnkgY2xhc3MgaW4gbW9jayBjb25kaXRpb24sIG1lYW4gb2YgdHdvIHJlcHMsIG1lZGlhbitpcXIiLGZpZy5sYWIuc2l6ZSA9IDYpCmdnc2F2ZSgiVmlvbGluX0NUQ0ZfY2xhc3Nlcy5wZGYiLGxhc3RfcGxvdCgpKQpgYGAKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcCA8LSBnZ3Zpb2xpbihyZXN1bHRzLHggPSJwcm8iLHk9Im1lYW4ubW9jayIsZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwsYWRkPSJtZWRpYW5faXFyIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMTApKQphbm5vdGF0ZV9maWd1cmUocCxmaWcubGFiID0gIkNUQ0Ygc2lnbmFsIGJ5IGNsYXNzIGluIG1vY2sgY29uZGl0aW9uLCBtZWFuIG9mIHR3byByZXBzLCBtZWRpYW4raXFyIixmaWcubGFiLnNpemUgPSA2KQpnZ3NhdmUoIlZpb2xpbl9DVENGX2NsYXNzZXNfcHJvLnBkZiIsbGFzdF9wbG90KCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KbWRmIDwtIHJlc2hhcGUyOjptZWx0KGRwbHlyOjpzZWxlY3QocmVzdWx0cyxjKCJjbGFzcyIsIm1vY2tfMSIsIm1vY2tfMiIsIlBEU18xIiwiUERTXzIiLCJQaGVuREMzXzEiLCJQaGVuREMzXzIiKSkpCmdnYm94cGxvdChtZGYseCA9InZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwgKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmdnc2F2ZSgiQm94cGxvdF9DVENGX3JlcHMucGRmIixsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdChyZXN1bHRzLGMoImNsYXNzIiwibW9ja18xIiwibW9ja18yIiwiUERTXzEiLCJQRFNfMiIsIlBoZW5EQzNfMSIsIlBoZW5EQzNfMiIpKSkKZ2d2aW9saW4obWRmLHggPSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsLGFkZD0ibWVkaWFuX2lxciIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDEwKSkKZ2dzYXZlKCJWaW9saW5fQ1RDRl9yZXBzLnBkZiIsbGFzdF9wbG90KCkpCmBgYApgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdChyZXN1bHRzLGMoImNsYXNzIiwiZGVzZXEubGZjLnBkcyIsImRlc2VxLmxmYy5wZGMiKSkpCnAgPC0gZ2d2aW9saW4obWRmLHggPSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsLCBhZGQ9Im1lZGlhbl9pcXIiKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMiwyKSkKYW5ub3RhdGVfZmlndXJlKHAsZmlnLmxhYiA9ICJERVNFcSBmb2xkY2hhbmdlIG1lYW4gdHJlYXQgdnMgbWVhbiBtb2NrLCBtZWRpYW4raXFyIixmaWcubGFiLnNpemUgPSA2KQpnZ3NhdmUoIlZpb2xpbl9DVENGX2xmYy5wZGYiLGxhc3RfcGxvdCgpKQpgYGAKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcCA8LSBnZ2JveHBsb3QobWRmLHggPSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMiwyKSkKYW5ub3RhdGVfZmlndXJlKHAsZmlnLmxhYiA9ICJERVNFcSBmb2xkY2hhbmdlIG1lYW4gdHJlYXQgdnMgbWVhbiBtb2NrLCBtZWRpYW4raXFyIixmaWcubGFiLnNpemUgPSA2KQpnZ3NhdmUoIkJveHBsb3RfQ1RDRl9sZmMucGRmIixsYXN0X3Bsb3QoKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdChyZXN1bHRzLGMoInBybyIsImNsYXNzIiwiZGVzZXEubGZjLnBkcyIsImRlc2VxLmxmYy5wZGMiKSkpCnAgPC0gZ2d2aW9saW4obWRmLHggPSJwcm8iLHk9InZhbHVlIixmaWxsPSJjbGFzcyIscGFsZXR0ZT1teXBhbCwgYWRkPSJtZWRpYW5faXFyIiwgZmFjZXQuYnk9InZhcmlhYmxlIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCxsaW5ldHlwZSA9ICJkb3R0ZWQiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTIsMikpCmFubm90YXRlX2ZpZ3VyZShwLGZpZy5sYWIgPSAiREVTRXEgZm9sZGNoYW5nZSBtZWFuIHRyZWF0IHZzIG1lYW4gbW9jaywgbWVkaWFuK2lxciIsZmlnLmxhYi5zaXplID0gNikKZ2dzYXZlKCJWaW9saW5fQ1RDRl9sZmNfcHJvLnBkZiIsbGFzdF9wbG90KCkpCmBgYAoKYGBge3J9CmNvbXBhcmVfbWVhbnMocmF3LmxmYy5wZHMgfiBjbGFzcyxkYXRhID0gcmVzdWx0cykKYGBgCgpgYGB7cn0KY29tcGFyZV9tZWFucyhyYXcubGZjLnBkYyB+IGNsYXNzLGRhdGEgPSByZXN1bHRzLCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdChyZXN1bHRzLGMoImNsYXNzIiwicmF3LmxmYy5wZHNfMSIsInJhdy5sZmMucGRzXzIiLCJyYXcubGZjLnBkY18xIiwicmF3LmxmYy5wZGNfMiIpKSkKZ2d2aW9saW4obWRmLHggPSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsLCBhZGQ9Im1lZGlhbl9pcXIiKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNCw0KSkKZ2dzYXZlKCJWaW9saW5fQ1RDRl9sZmNfaW5kaXZpZHVhbF9yZXBzLnBkZiIsbGFzdF9wbG90KCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2dkZW5zaXR5KHJlc3VsdHMseD0icmF3LmxmYy5wZHMiLGNvbG9yPSJjbGFzcyIsIGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0iZG90dGVkIikKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ2RlbnNpdHkocmVzdWx0cyx4PSJyYXcubGZjLnBkYyIsY29sb3I9ImNsYXNzIiwgZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSJkb3R0ZWQiKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpnZ3NjYXR0ZXJoaXN0KHJlc3VsdHMseCA9ImxvZzIubW9jayIseT0ibG9nMi5wZHMiLHNpemUgPSAwLjIsIGFscGhhPTAuMSxjb2xvcj0iZGVzZXEuc2lnLnBkcyIsbWFyZ2luLnBhcmFtcyA9IGxpc3QoZmlsbD0iY2xhc3MiLGNvbG9yPSJibGFjayIsc2l6ZT0wLjIpLHBhbGV0dGU9bXlwYWxbYyg1LDIpXSkKZ2dzYXZlKCJTY2F0dGVyX0NUQ0ZfREVTRXFfUERTdnNNb2NrLnBkZiIsbGFzdF9wbG90KCkpCmBgYApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpnZ3NjYXR0ZXJoaXN0KHJlc3VsdHMseCA9ImxvZzIubW9jayIseT0ibG9nMi5wZGMiLHNpemUgPSAwLjIsIGFscGhhPTAuMSxjb2xvcj0iZGVzZXEuc2lnLnBkcyIsbWFyZ2luLnBhcmFtcyA9IGxpc3QoZmlsbD0iY2xhc3MiLGNvbG9yPSJibGFjayIsc2l6ZT0wLjIpLHBhbGV0dGU9bXlwYWxbYyg1LDIpXSkKZ2dzYXZlKCJTY2F0dGVyX0NUQ0ZfREVTRXFfUGhlbkRDM3ZzTW9jay5wZGYiLGxhc3RfcGxvdCgpKQpgYGAKCmBgYHtyfQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCkscmVzdWx0cyRwcm8pCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9Mi41fQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCkscmVzdWx0cyRjbGFzcykKbWRmPC1yZXNoYXBlMjo6bWVsdCh0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCkscmVzdWx0cyRjbGFzcykpCmdncGxvdChtZGYsYWVzKFZhcjEsIFZhcjIsIGZpbGw9IHZhbHVlKSkgKyAKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWw9dmFsdWUpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD0ib3JhbmdlIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgpgYGB7cn0KdmwgPC0gbGlzdChzaWc9Z3JlcCgiVFJVRSIscmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMpLENUQ0ZfRzQ9Z3JlcCgiYW5kIixyZXN1bHRzJGNsYXNzKSxDVENGb25seT1ncmVwKCJub3QiLHJlc3VsdHMkY2xhc3MpKQpwbG90KGV1bGVyKHZsKSxxdWFudGl0aWVzPVQpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9Mi41fQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZGMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRjID4gMCkscmVzdWx0cyRjbGFzcykKbWRmPC1yZXNoYXBlMjo6bWVsdCh0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZGMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRjID4gMCkscmVzdWx0cyRjbGFzcykpCmdncGxvdChtZGYsYWVzKFZhcjEsIFZhcjIsIGZpbGw9IHZhbHVlKSkgKyAKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWw9dmFsdWUpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD0ib3JhbmdlIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgoKYGBge3J9CnJlc3VsdHMkdWlkIDwtIHNlcSgxOm5yb3cocmVzdWx0cykpCnZsIDwtIGxpc3Qoc2lnPWdyZXAoIlRSVUUiLHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKSxDVENGX0c0PWdyZXAoImFuZCIscmVzdWx0cyRjbGFzcyksQ1RDRm9ubHk9Z3JlcCgibm90IixyZXN1bHRzJGNsYXNzKSkKcGxvdChldWxlcih2bCkscXVhbnRpdGllcz1UKQpgYGAKIApgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0yLjV9CnRhYmxlKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzLHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKQptZGY8LXJlc2hhcGUyOjptZWx0KHRhYmxlKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzLHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKSkKZ2dwbG90KG1kZixhZXMoVmFyMSwgVmFyMiwgZmlsbD0gdmFsdWUpKSArIAogIGdlb21fdGlsZShzaG93LmxlZ2VuZCA9IEYpICsgZ2VvbV90ZXh0KGFlcyhsYWJlbD12YWx1ZSkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0id2hpdGUiLCBoaWdoPSJvcmFuZ2UiKSArIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQp2bCA8LSBsaXN0KHNpZ19QRFM9Z3JlcCgiVFJVRSIscmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMpLHNpZ19QREM9Z3JlcCgiVFJVRSIscmVzdWx0cyRkZXNlcS5zaWd1cC5wZGMpLENUQ0ZfRzQ9Z3JlcCgiYW5kIixyZXN1bHRzJGNsYXNzKSxDVENGb25seT1ncmVwKCJub3QiLHJlc3VsdHMkY2xhc3MpKQpwbG90KGV1bGVyKHZsKSxxdWFudGl0aWVzPVQpCmBgYAoKYGBge3J9CnJlc3VsdHMkdWlkIDwtIHNlcSgxOm5yb3cocmVzdWx0cykpCnZsIDwtIGxpc3Qoc2lnX1BEUz1ncmVwKCJUUlVFIixyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyksc2lnX1BEQz1ncmVwKCJUUlVFIixyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYyksQ1RDRl9HND1ncmVwKCJhbmQiLHJlc3VsdHMkY2xhc3MpKQpwbG90KGV1bGVyKHZsKSxxdWFudGl0aWVzPVQpCmBgYApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpyZXN1bHRzJHNpZy5ieS5jbGFzcy5wZHMgPC0gcGFzdGUwKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzLCJfIixyZXN1bHRzJGNsYXNzKQpyZXN1bHRzJHBzaXplIDwtIDAuMDEKcmVzdWx0cyRwc2l6ZVtyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyAmIHJlc3VsdHMkY2xhc3M9PSJDVENGX2FuZF9HNCJdIDwtIDEKCmdnc2NhdHRlcihyZXN1bHRzLHggPSJsb2cyLm1vY2siLHk9ImxvZzIucGRzIixzaXplID0gMC41LCBhbHBoYT1yZXN1bHRzJHBzaXplLGNvbG9yID0gInNpZy5ieS5jbGFzcy5wZHMiLHBhbGV0dGU9YyhteXBhbFs1XSxteXBhbFs1XSxteXBhbFs1XSxteXBhbFsyXSxteXBhbFsxXSkpCmBgYApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpnZ3NjYXR0ZXIocmVzdWx0c1shZ3JlcGwoIk5BIixyZXN1bHRzJHNpZy5ieS5jbGFzcy5wZHMpLF0seCA9ImxvZzIubW9jayIseT0iZGVzZXEubGZjLnBkcyIsc2l6ZSA9IDAuMiwgYWxwaGE9InBzaXplIixjb2xvciA9ICJzaWcuYnkuY2xhc3MucGRzIixwYWxldHRlPWMoIiM1MDUwNTAiLCIjNTA1MDUwIiwicmVkMiIsImJsdWUiKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQpnZ3NjYXR0ZXJoaXN0KHJlc3VsdHNbIWdyZXBsKCJOQSIscmVzdWx0cyRzaWcuYnkuY2xhc3MucGRzKSxdLHggPSJsb2cyLm1vY2siLHk9ImxvZzIucGRzIixzaXplID0gMC40LCBhbHBoYT0icHNpemUiLGNvbG9yID0gInNpZy5ieS5jbGFzcy5wZHMiLG1hcmdpbi5wYXJhbXMgPSBsaXN0KGZpbGw9InNpZy5ieS5jbGFzcy5wZHMiLGNvbG9yPSJibGFjayIsc2l6ZT0wLjIpLHBhbGV0dGU9YygiIzUwNTA1MCIsIiM1MDUwNTAiLCJyZWQyIiwiYmx1ZSIpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9Cmdnc2NhdHRlcihyZXN1bHRzLHggPSJyYXcubGZjLnBkcyIseT0ibG9nMi5HNCIsc2l6ZSA9IDAuMiwgYWxwaGE9MC4xLGNvbG9yPSJkZXNlcS5zaWd1cC5wZHMiKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpyZXN1bHRzJEc0LnF1YW50aWxlIDwtIGN1dF9udW1iZXIocmVzdWx0cyRHNF9OVCwgbiA9IDUsbGFiZWxzPUYpCmdnc3RyaXBjaGFydChyZXN1bHRzLHg9Ikc0LnF1YW50aWxlIiwgeT0iZGVzZXEubGZjLnBkcyIsY29sb3I9bXlwYWxbMl0sYWRkPWMoInZpb2xpbiIsIm1lZGlhbl9pcXIiKSxhZGQucGFyYW1zPWxpc3QoY29sb3I9ImJsYWNrIixmaWxsPW15cGFsWzFdKSxzaXplPTAuMiwgYWxwaGE9cmVzdWx0cyRkZXNlcS5zaWcucGRzLzQsIHBhbGV0dGU9bXlwYWwpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMywzKSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZG90dGVkIikKZ2dzYXZlKCJWaW9saW5fQ1RDRl9sZmNfYnlfRzRxdWFudGlsZV9zaWdfaGlnaGxpZ2h0ZWQucGRmIikKYGBgCmBgYHtyfQp0YWJsZShyZXN1bHRzJEc0LnF1YW50aWxlLHJlc3VsdHMkZGVzZXEuc2lnLnBkcykKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbihyZXN1bHRzLHg9Ikc0LnF1YW50aWxlIiwgeT0iZGVzZXEubGZjLnBkcyIsZmlsbD1teXBhbFsxXSxhZGQ9Im1lZGlhbl9pcXIiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTIsMikpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRvdHRlZCIpCmdnc2F2ZSgiVmlvbGluX0NUQ0ZfbGZjX2J5X0c0cXVhbnRpbGUucGRmIikKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbihyZXN1bHRzLHg9Ikc0LnF1YW50aWxlIiwgeT0ibG9nMi5HNCIsZmlsbD1teXBhbDJbNV0sYWRkPSJtZWRpYW5faXFyIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZG90dGVkIikKZ2dzYXZlKCJWaW9saW5fRzRfYnlfRzRxdWFudGlsZS5wZGYiKQpgYGAKCgoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGVha19jYXRzIDwtIGJlZHNjb3V0OjppbXBvcnRfbmFtZWRfYmVkX2ludG9fbGlzdChwZWFrc19iZWQpCnBsb3RfYndfcHJvZmlsZSgiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L0dTTTY2MzQzMjVfRTE0X01vY2tfRzQuYnciLHBlYWtfY2F0cyxsYWJlbHM9YyhwZWFrX2NhdHNbWzFdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzJdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzNdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzRdXVsxLF0kbmFtZSksbW9kZT0iY2VudGVyIixzaG93X2Vycm9yID0gVCx2ZXJib3NlPUYsIHJlbW92ZV90b3A9MC4wMDEsIGNvbG9ycz1teXBhbCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwZWFrX2NhdHMgPC0gYmVkc2NvdXQ6OmltcG9ydF9uYW1lZF9iZWRfaW50b19saXN0KHBlYWtzX2JlZCkKcGxvdF9id19wcm9maWxlKEc0X2JpZ3dpZ3MscGVha19jYXRzLGxhYmVscz1jKHBlYWtfY2F0c1tbMV1dWzEsXSRuYW1lLHBlYWtfY2F0c1tbMl1dWzEsXSRuYW1lLHBlYWtfY2F0c1tbM11dWzEsXSRuYW1lLHBlYWtfY2F0c1tbNF1dWzEsXSRuYW1lKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CnBsb3RfYndfcHJvZmlsZShtb2Nrc19iaWd3aWdzWzFdLHBlYWtfY2F0cyxsYWJlbHM9YyhwZWFrX2NhdHNbWzFdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzJdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzNdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzRdXVsxLF0kbmFtZSksbW9kZT0iY2VudGVyIixzaG93X2Vycm9yID0gVCx2ZXJib3NlPUYsIHJlbW92ZV90b3A9MC4wMDEsIGNvbG9ycz1teXBhbCkKYGBgCgoKCgpgYGB7ciBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9M30KcDEgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1sxXV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCw1LDYpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKcDIgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1syXV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCw1LDYpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKcDMgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1szXV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCw1LDYpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKcDQgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1s0XV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCw1LDYpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKCmdnYXJyYW5nZShwMSxwMixwMyxwNCxuY29sID0gNCxucm93ID0gMSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9M30KcDEgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1sxXV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCwzLDQpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKcDIgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1syXV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCwzLDQpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKcDMgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1szXV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCwzLDQpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKcDQgPC0gcGxvdF9id19wcm9maWxlKGMobW9ja3NfYmlnd2lncyxwZHNfYmlnd2lncykscGVha19jYXRzW1s0XV0sbGFiZWxzPWMoIm1vY2sxIiwibW9jazIiLCJ0cnQxIiwicnRyMiIpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwyW2MoOSwxMCwzLDQpXSx1cHN0cmVhbSA9IDE1MDAsIGRvd25zdHJlYW09MTUwMCkKCmdnYXJyYW5nZShwMSxwMixwMyxwNCxuY29sID0gNCxucm93ID0gMSkKYGBgCiMjIyBjZW4gd2UgbGVhcm4gc29tZXRoaW5nIGZyb20gdGhlIGdlbmVzIHdpdGggdG9wLW1vc3QgaW5jcmVhc2UgaW4gQ1RDRj8KYGBge3J9CnNpZ3VwLnBkcyA8LSByZXN1bHRzW3Jlc3VsdHMkZGVzZXEuc2lndXAucGRzLF0Kc2lndXAucGRjIDwtIHJlc3VsdHNbcmVzdWx0cyRkZXNlcS5zaWd1cC5wZGMsXQoKI2V4cG9ydC5iZWQoc2lndXAucGRzLCJwZWFrc19zaWd1cF9wZHMuYmVkIikKI2V4cG9ydC5iZWQoc2lndXAucGRzLCJwZWFrc19zaWd1cF9wZHMuYmVkIikKYGBgCgoKYGBge3J9CmdnaGlzdG9ncmFtKHJlc3VsdHMsIndpZHRoIiwgYWRkPSJtZWRpYW4iLCBmaWxsPSJjbGFzcyIpCmBgYAojIyMgT3ZlcmxhcCBhbmFseXNpcwoKYGBge3J9Ckc0X2JlZCA8LSBpbXBvcnQoJy4uL2RhdGEvRzRfQ25UL0c0X1dUX3BlYWtzLm5hcnJvd1BlYWsnKQpBVEFDX2JlZCA8LSBpbXBvcnQoJy4uL2RhdGEvQVRBQy1zZXEvQVRBQ19zZXFfbUVTQ19NYXJ0aXJlX3BlYWtzLm5hcnJvd1BlYWsnKQpwcm9fYmVkIDwtIGltcG9ydCgnLi4vZGF0YS9yZWdpb25zL3Byb21vdGVyc19nZW5lU3ltYm9sLm1tMTAuYmVkJykKCkc0X2JlZCA8LSBiZWRzY291dDo6YW5ub3RhdGVfb3ZlcmxhcHBpbmdfZmVhdHVyZXMoRzRfYmVkLHByb19iZWQsbmFtZV9maWVsZCA9ICJuYW1lIikKCkc0X2JlZCRuYW1lIDwtICJHNCIKRzRfYmVkJG5hbWVbIWlzLm5hKEc0X2JlZCRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiRzRwcm8iCkc0X2JlZCRuYW1lW2dyZXBsKCJwcm8iLEc0X2JlZCRuYW1lKV0gPC0gIkc0cHJvIgpgYGAKCmBgYHtyfQpuZWFyZXN0X0c0XzFrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKGN0Y2YsRzRfYmVkLGRpc3RhbmNlX2N1dG9mZiA9IDEwMDAsaWdub3JlLnN0cmFuZCA9IFQsbmFtZV9maWVsZCA9ICJuYW1lIikKbmVhcmVzdF9HNF8yLjVrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKGN0Y2YsRzRfYmVkLGRpc3RhbmNlX2N1dG9mZiA9IDI1MDAsaWdub3JlLnN0cmFuZCA9IFQsbmFtZV9maWVsZCA9ICJuYW1lIikKbmVhcmVzdF9HNF81a2IgPC0gYmVkc2NvdXQ6OmFubm90YXRlX25lYXJieV9mZWF0dXJlcyhjdGNmLEc0X2JlZCxkaXN0YW5jZV9jdXRvZmYgPSA1MDAwLGlnbm9yZS5zdHJhbmQgPSBULG5hbWVfZmllbGQgPSAibmFtZSIpCm5lYXJlc3RfRzRfMTBrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKGN0Y2YsRzRfYmVkLGRpc3RhbmNlX2N1dG9mZiA9IDEwMDAwLGlnbm9yZS5zdHJhbmQgPSBULG5hbWVfZmllbGQgPSAibmFtZSIpCm5lYXJlc3RfRzRfNTBrYiA8LSBiZWRzY291dDo6YW5ub3RhdGVfbmVhcmJ5X2ZlYXR1cmVzKGN0Y2YsRzRfYmVkLGRpc3RhbmNlX2N1dG9mZiA9IDUwMDAwLGlnbm9yZS5zdHJhbmQgPSBULG5hbWVfZmllbGQgPSAibmFtZSIpCgpjdGNmJG5lYXJlc3RfRzQgPC0gZmFjdG9yKCI+NTBrYiIsIGxldmVscz1jKCI8MWtiIiwiPDIuNWtiIiwiPDVrYiIsIjwxMGtiIiwiPDUwa2IiLCI+NTBrYiIpKQpjdGNmJG5lYXJlc3RfRzRbIWlzLm5hKG5lYXJlc3RfRzRfNTBrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiPDUwa2IiCmN0Y2YkbmVhcmVzdF9HNFshaXMubmEobmVhcmVzdF9HNF8xMGtiJG5lYXJieV9mZWF0dXJlcyldIDwtICI8MTBrYiIKY3RjZiRuZWFyZXN0X0c0WyFpcy5uYShuZWFyZXN0X0c0XzVrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSAiPDVrYiIKY3RjZiRuZWFyZXN0X0c0WyFpcy5uYShuZWFyZXN0X0c0XzIuNWtiJG5lYXJieV9mZWF0dXJlcyldIDwtICI8Mi41a2IiCmN0Y2YkbmVhcmVzdF9HNFshaXMubmEobmVhcmVzdF9HNF8xa2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gIjwxa2IiCgpjdGNmJG5lYXJlc3RfRzRfdHlwZSA8LSAibm9uZSIKY3RjZiRuZWFyZXN0X0c0X3R5cGVbIWlzLm5hKG5lYXJlc3RfRzRfNTBrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSBuZWFyZXN0X0c0XzUwa2IkbmVhcmJ5X2ZlYXR1cmVzWyFpcy5uYShuZWFyZXN0X0c0XzUwa2IkbmVhcmJ5X2ZlYXR1cmVzKV0KY3RjZiRuZWFyZXN0X0c0X3R5cGVbIWlzLm5hKG5lYXJlc3RfRzRfMTBrYiRuZWFyYnlfZmVhdHVyZXMpXSA8LSBuZWFyZXN0X0c0XzEwa2IkbmVhcmJ5X2ZlYXR1cmVzWyFpcy5uYShuZWFyZXN0X0c0XzEwa2IkbmVhcmJ5X2ZlYXR1cmVzKV0KY3RjZiRuZWFyZXN0X0c0X3R5cGVbIWlzLm5hKG5lYXJlc3RfRzRfNWtiJG5lYXJieV9mZWF0dXJlcyldIDwtIG5lYXJlc3RfRzRfNWtiJG5lYXJieV9mZWF0dXJlc1shaXMubmEobmVhcmVzdF9HNF81a2IkbmVhcmJ5X2ZlYXR1cmVzKV0KY3RjZiRuZWFyZXN0X0c0X3R5cGVbIWlzLm5hKG5lYXJlc3RfRzRfMi41a2IkbmVhcmJ5X2ZlYXR1cmVzKV0gPC0gbmVhcmVzdF9HNF8yLjVrYiRuZWFyYnlfZmVhdHVyZXNbIWlzLm5hKG5lYXJlc3RfRzRfMi41a2IkbmVhcmJ5X2ZlYXR1cmVzKV0KY3RjZiRuZWFyZXN0X0c0X3R5cGVbIWlzLm5hKG5lYXJlc3RfRzRfMWtiJG5lYXJieV9mZWF0dXJlcyldIDwtIG5lYXJlc3RfRzRfMWtiJG5lYXJieV9mZWF0dXJlc1shaXMubmEobmVhcmVzdF9HNF8xa2IkbmVhcmJ5X2ZlYXR1cmVzKV0KCmN0Y2YkbmVhcmVzdF9HNF90eXBlW2dyZXAoInBybyIsY3RjZiRuZWFyZXN0X0c0X3R5cGUpXSA8LSAiRzRwcm8iCgpyZXN1bHRzJG5lYXJlc3RfRzQgPC0gY3RjZiRuZWFyZXN0X0c0CnJlc3VsdHMkbmVhcmVzdF9HNF90eXBlIDwtIGN0Y2YkbmVhcmVzdF9HNF90eXBlCnRhYmxlKHJlc3VsdHMkbmVhcmVzdF9HNCkKdGFibGUocmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUpCnRhYmxlKHJlc3VsdHMkbmVhcmVzdF9HNCwgcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGUpCmBgYApgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbihyZXN1bHRzLHg9Im5lYXJlc3RfRzQiLCB5PSJtZWFuLm1vY2siLGZpbGw9bXlwYWxbMV0sYWRkPSJtZWRpYW5faXFyIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMTApKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkb3R0ZWQiKQpnZ3NhdmUoIlZpb2xpbl9DVENGX3NpZ25hbF9ieV9HNGRpc3RhbmNlLnBkZiIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4ocmVzdWx0cyx4PSJuZWFyZXN0X0c0IiwgeT0iZGVzZXEubGZjLnBkcyIsZmlsbD1teXBhbFsxXSxhZGQ9Im1lZGlhbl9pcXIiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTIsMikpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxsaW5ld2lkdGggPSAwLjIgKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lZGlhbihyZXN1bHRzJGRlc2VxLmxmYy5wZHNbcmVzdWx0cyRuZWFyZXN0X0c0PT0iPDFrYiJdKSwgbGluZXR5cGU9ImRvdHRlZCIsbGluZXdpZHRoID0gMC4yKQpnZ3NhdmUoIlZpb2xpbl9DVENGX1BEU19sZmNfYnlfRzRkaXN0YW5jZS5wZGYiKQpgYGAKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkcyB+IG5lYXJlc3RfRzQsIHJlc3VsdHMpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4ocmVzdWx0cyx4PSJuZWFyZXN0X0c0IiwgeT0iZGVzZXEubGZjLnBkYyIsZmlsbD1teXBhbFsxXSxhZGQ9Im1lZGlhbl9pcXIiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTIsMikpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxsaW5ld2lkdGggPSAwLjIgKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lYW4ocmVzdWx0cyRkZXNlcS5sZmMucGRjW3Jlc3VsdHMkbmVhcmVzdF9HND09Ijwxa2IiXSksIGxpbmV0eXBlPSJkb3R0ZWQiLGxpbmV3aWR0aCA9IDAuMikKZ2dzYXZlKCJWaW9saW5fQ1RDRl9QaGVuREMzX2xmY19ieV9HNGRpc3RhbmNlLnBkZiIpCmBgYAoKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IG5lYXJlc3RfRzQsIHJlc3VsdHMpCmBgYApgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0zfQpnZ3Zpb2xpbihyZXN1bHRzLHg9Im5lYXJlc3RfRzQiLCB5PSJkZXNlcS5sZmMucGRzIixmaWxsPSJuZWFyZXN0X0c0X3R5cGUiLHBhbGV0dGU9bXlwYWxbYygxLDMsNSldLGFkZD0ibWVkaWFuX2lxciIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMiwyKSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLGxpbmV3aWR0aCA9IDAuMiApICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbihyZXN1bHRzJGRlc2VxLmxmYy5wZHNbcmVzdWx0cyRuZWFyZXN0X0c0PT0iPDFrYiJdKSwgbGluZXR5cGU9ImRvdHRlZCIsbGluZXdpZHRoID0gMC4yKQpnZ3NhdmUoIlZpb2xpbl9DVENGX1BEU19sZmNfYnlfRzRkaXN0YW5jZV9wcm8ucGRmIikKYGBgCmBgYHtyfQpjb21wYXJlX21lYW5zKGRlc2VxLmxmYy5wZHMgfiBuZWFyZXN0X0c0LCByZXN1bHRzW3Jlc3VsdHMkbmVhcmVzdF9HNF90eXBlPT0iRzQiLF0pCmBgYApgYGB7cn0KY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRzIH4gbmVhcmVzdF9HNCwgcmVzdWx0c1tyZXN1bHRzJG5lYXJlc3RfRzRfdHlwZT09Ikc0cHJvIixdKQpgYGAKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4ocmVzdWx0cyx4PSJuZWFyZXN0X0c0IiwgeT0iZGVzZXEubGZjLnBkYyIsZmlsbD0ibmVhcmVzdF9HNF90eXBlIixwYWxldHRlPW15cGFsW2MoMSwzLDUpXSxhZGQ9Im1lZGlhbl9pcXIiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTIsMikpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxsaW5ld2lkdGggPSAwLjIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbihyZXN1bHRzJGRlc2VxLmxmYy5wZGNbcmVzdWx0cyRuZWFyZXN0X0c0PT0iPDFrYiJdKSwgbGluZXR5cGU9ImRvdHRlZCIsbGluZXdpZHRoID0gMC4yKQpnZ3NhdmUoIlZpb2xpbl9DVENGX1BoZW5EQzNfbGZjX2J5X0c0ZGlzdGFuY2VfcHJvLnBkZiIpCmBgYAoKYGBge3J9CmNvbXBhcmVfbWVhbnMoZGVzZXEubGZjLnBkYyB+IG5lYXJlc3RfRzQsIHJlc3VsdHNbcmVzdWx0cyRuZWFyZXN0X0c0X3R5cGU9PSJHNCIsXSkKYGBgCgpgYGB7cn0KY29tcGFyZV9tZWFucyhkZXNlcS5sZmMucGRjIH4gbmVhcmVzdF9HNCwgcmVzdWx0c1tyZXN1bHRzJG5lYXJlc3RfRzRfdHlwZT09Ikc0cHJvIixdKQpgYGAKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGVha19jYXRzIDwtIGJlZHNjb3V0OjppbXBvcnRfbmFtZWRfYmVkX2ludG9fbGlzdChwZWFrc19iZWQpCnBsb3RfYndfcHJvZmlsZSgiLi4vZGF0YS9yZWdpb25zL0c0Lm1tMTAucGx1cy5idyIscGVha19jYXRzLGxhYmVscz1jKHBlYWtfY2F0c1tbMV1dWzEsXSRuYW1lLHBlYWtfY2F0c1tbMl1dWzEsXSRuYW1lLHBlYWtfY2F0c1tbM11dWzEsXSRuYW1lLHBlYWtfY2F0c1tbNF1dWzEsXSRuYW1lKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgY29sb3JzPW15cGFsKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CnBlYWtfY2F0cyA8LSBiZWRzY291dDo6aW1wb3J0X25hbWVkX2JlZF9pbnRvX2xpc3QocGVha3NfYmVkKQpwbG90X2J3X3Byb2ZpbGUoIi4uL2RhdGEvcmVnaW9ucy9HNC5tbTEwLm1pbnVzLmJ3IixwZWFrX2NhdHMsbGFiZWxzPWMocGVha19jYXRzW1sxXV1bMSxdJG5hbWUscGVha19jYXRzW1syXV1bMSxdJG5hbWUscGVha19jYXRzW1szXV1bMSxdJG5hbWUscGVha19jYXRzW1s0XV1bMSxdJG5hbWUpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCBjb2xvcnM9bXlwYWwpCmBgYApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpwZWFrX2NhdHNfbW05IDwtIGJlZHNjb3V0OjppbXBvcnRfbmFtZWRfYmVkX2ludG9fbGlzdCgnLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXMubW05bGlmdC5iZWQnKQpwbG90X2J3X3Byb2ZpbGUoIn4vR29vZ2xlIERyaXZlL1NpbW9uL01hbnVzY3JpcHRzL1B1Y2svZ2l0aHViL2dlbm9tZS9tbTkvcHJlZEc0Lm1tOS5idyIscGVha19jYXRzX21tOSxsYWJlbHM9YyhwZWFrX2NhdHNfbW05W1sxXV1bMSxdJG5hbWUscGVha19jYXRzX21tOVtbMl1dWzEsXSRuYW1lLHBlYWtfY2F0c19tbTlbWzNdXVsxLF0kbmFtZSxwZWFrX2NhdHNfbW05W1s0XV1bMSxdJG5hbWUpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCBjb2xvcnM9bXlwYWwpCmBgYApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpwZWFrX2NhdHNfbW05IDwtIGJlZHNjb3V0OjppbXBvcnRfbmFtZWRfYmVkX2ludG9fbGlzdCgnLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl8yX2NhdGVnb3JpZXMubW05bGlmdC5iZWQnKQpwbG90X2J3X3Byb2ZpbGUoIn4vR29vZ2xlIERyaXZlL1NpbW9uL01hbnVzY3JpcHRzL1B1Y2svZ2l0aHViL2dlbm9tZS9tbTkvcHJlZEc0Lm1tOS5idyIscGVha19jYXRzX21tOSxsYWJlbHM9YyhwZWFrX2NhdHNfbW05W1sxXV1bMSxdJG5hbWUscGVha19jYXRzX21tOVtbMl1dWzEsXSRuYW1lKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgY29sb3JzPW15cGFsLGJpbl9zaXplID0gMjAwKQpnZ3NhdmUoIlByb2ZpbGVfcHJlZGljdGVkX0c0X21vdGlmLnBkZiIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KcDEgPC0gcGxvdF9id19oZWF0bWFwKCJ+L0dvb2dsZSBEcml2ZS9TaW1vbi9NYW51c2NyaXB0cy9QdWNrL2dpdGh1Yi9nZW5vbWUvbW05L3ByZWRHNC5tbTkuYnciLHBlYWtfY2F0c19tbTlbWzFdXSxtb2RlPSJjZW50ZXIiLHZlcmJvc2U9RixtYXhfcm93c19hbGxvd2VkID0gNTAwLCB6bWF4PTAuMyxjbWFwPSJHcmV5cyIpICsgZ2d0aXRsZSgiQ1RDRi1HNCIpCnAyIDwtIHBsb3RfYndfaGVhdG1hcCgifi9Hb29nbGUgRHJpdmUvU2ltb24vTWFudXNjcmlwdHMvUHVjay9naXRodWIvZ2Vub21lL21tOS9wcmVkRzQubW05LmJ3IixwZWFrX2NhdHNfbW05W1syXV0sbW9kZT0iY2VudGVyIix2ZXJib3NlPUYsbWF4X3Jvd3NfYWxsb3dlZCA9IDUwMCwgem1heD0wLjMsY21hcD0iR3JleXMiKSArIGdndGl0bGUoIkNUQ0Ytb25seSIpCmdnYXJyYW5nZShwMSxwMikKZ2dzYXZlKCJIZWF0bWFwX3ByZWRpY3RlZF9HNF9tb3RpZi5wZGYiKQpgYGA=